﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Dycox.Linq
{
    internal static class TypicalLinqMethods
    {
        static Dictionary<string, MethodInfo> _methods;

        private static void EnsureInitialized()
        {
            if (_methods == null)
            {
                _methods = new Dictionary<string, MethodInfo>();

                typeof(Enumerable).FindMembers(MemberTypes.Method, BindingFlags.Static | BindingFlags.Public,
                    (info, c) =>
                    {
                        string name = info.Name;
                        if (name == "Contains")
                        {
                            MethodInfo m = (MethodInfo)info;
                            if (m.GetParameters().Length == 2)
                            {
                                _methods.Add("Enumerable" + name, m);
                                return true;
                            }
                        }
                        else if (name == "ToArray")
                            _methods.Add(name, (MethodInfo)info);
                        return false;
                    }
                , null);

                typeof(Queryable).FindMembers(MemberTypes.Method, BindingFlags.Static | BindingFlags.Public,
                    (info, c) =>
                    {
                        string name = info.Name;
                        if (name == "OrderBy" || name == "OrderByDescending" || name == "ThenBy" || name == "ThenByDescending")
                        {
                            MethodInfo m = (MethodInfo)info;
                            if (m.GetParameters().Length == 2)
                            {
                                _methods.Add("Queryable" + name, m);
                                return true;
                            }
                        }
                        if (name == "Select")
                        {
                            MethodInfo m = (MethodInfo)info;
                            if (m.GetParameters()[1].ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2)
                                _methods.Add("Queryable" + name, m);
                        }
                        else if (name == "Count")
                        {
                            MethodInfo m = (MethodInfo)info;
                            if (m.GetParameters().Length == 1)
                                _methods.Add("Queryable" + name, m);
                        }
                        else if (name == "Skip" || name == "Take")
                            _methods.Add("Queryable" + name, (MethodInfo)info);

                        return false;
                    }
                , null);


                Type type = typeof(string);
                _methods["StringStartsWith"] = type.GetMethod("StartsWith", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { type }, null);
                _methods["StringEndsWidth"] = type.GetMethod("EndsWith", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { type }, null);
                _methods["StringContains"] = type.GetMethod("Contains", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { type }, null);

            }
        }

        public static MethodInfo QueryableOrderBy
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableOrderBy"];
            }
        }

        public static MethodInfo QueryableOrderByDescending
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableOrderByDescending"];
            }
        }

        public static MethodInfo QueryableThenBy
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableThenBy"];
            }
        }

        public static MethodInfo QueryableThenByDescending
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableThenByDescending"];
            }
        }

        public static MethodInfo EnumerableContains
        {
            get
            {
                EnsureInitialized();
                return _methods["EnumerableContains"];
            }
        }

        public static MethodInfo GetMethod(string name)
        {
            EnsureInitialized();

            MethodInfo method;

            if (_methods.TryGetValue(name, out method))
                return method;

            throw new ArgumentException(SR.GetString("tlm_method_not_found", name));
        }

        public static MethodInfo StringStartsWith
        {
            get
            {
                EnsureInitialized();
                return _methods["StringStartsWith"];
            }
        }

        public static MethodInfo StringEndsWith
        {
            get
            {
                EnsureInitialized();
                return _methods["StringEndsWith"];
            }
        }

        public static MethodInfo StringContains
        {
            get
            {
                EnsureInitialized();
                return _methods["StringContains"];
            }
        }

        public static MethodInfo QueryableSelect
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableSelect"];
            }
        }

        public static MethodInfo QueryableSkip
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableSkip"];
            }
        }

        public static MethodInfo QueryableTake
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableTake"];
            }
        }

        public static MethodInfo ToArray
        {
            get
            {
                EnsureInitialized();
                return _methods["ToArray"];
            }
        }

        public static MethodInfo QueryableCount
        {
            get
            {
                EnsureInitialized();
                return _methods["QueryableCount"];
            }
        }
    }
}
